package io.github.javpower.imagerex.service;


import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.collect.Lists;
import io.github.javpower.imagerex.mapper.ImageMapper;
import io.github.javpower.imagerex.model.Image;
import io.github.javpower.imagerex.req.ImageReq;
import io.github.javpower.imagerex.res.PageResult;
import io.github.javpower.imagerex.util.PaginationUtil;
import io.github.javpower.vectorexbootstater.builder.LambdaQueryWrapper;
import io.github.javpower.vectorexbootstater.core.VectoRexResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;

@Service
@Slf4j
public class VectorExService {
    private final ImageMapper imageMapper;
    private final FeatureExtractor featureExtractor;
    // 🔹 内存缓存：自动过期 10 分钟，最大 100 条缓存
    private final Cache<String, List<Image>> memoryCache = Caffeine.newBuilder()
            .maximumSize(100)
            .build();

    public VectorExService(FeatureExtractor featureExtractor, ImageMapper imageMapper) {
        this.featureExtractor = featureExtractor;
        this.imageMapper = imageMapper;
    }

    public String deleteImageByName(String name) {
        try {
            // 调用服务删除指定名称的图片实体
            boolean deleted = del(name);
            if (deleted) {
                return "删除图片 '" + name + "' 成功!";
            } else {
                return "未找到 '" + name + "' 这张图片!";
            }
        } catch (Exception e) {
            return "Error deleting the image: " + e.getMessage();
        }
    }

    public String uploadSingleImage(MultipartFile file) {
        if (!isImage(file.getContentType())) {
            return "该文件不是图片!";
        }
        File modelFile = new File("models/vgg19_dl4j_inference.zip");
        System.out.println(modelFile.getAbsoluteFile().toString());
        File tempFile = null;
        try {
            // 创建临时文件
                        tempFile = File.createTempFile("temp", null);
                Files.copy(file.getInputStream(), tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

                // 提取特征向量
                List<Float> vector;
                try {
                    vector = featureExtractor.getVectorFeatures(tempFile.getAbsolutePath());
            } catch (Exception e) {
                log.error(file.getOriginalFilename() + " extract vector error", e);
                throw new RuntimeException("Feature extraction failed", e);
            }

            // 将图片转换为 base64 编码
            String base64Image = encodeFileToBase64Binary(tempFile.getAbsolutePath());

            // 创建 Image 实体类
            Image image = new Image(file.getOriginalFilename(),  base64Image,LocalDateTime.now(), vector);

            // 保存到数据库或向量数据库
            saveImages(Lists.newArrayList(image));
            memoryCache.invalidateAll();
            return "图片上传成功!";
        } catch (IOException e) {
            log.error("File processing error", e);
            throw new RuntimeException("File processing error", e);
        } finally {
            // 确保临时文件被删除
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete();
            }
        }
    }


    public String uploadZipFile(MultipartFile file) {
        if (!file.getContentType().equals("application/zip")) {
            throw new IllegalArgumentException("该文件不是zip压缩包!");
        }
        List<Image> images = new ArrayList<>();
        try (InputStream is = file.getInputStream();
             ZipArchiveInputStream zis = new ZipArchiveInputStream(
                     new BufferedInputStream(is), "UTF-8")) {
            ZipEntry entry;
            while ((entry = zis.getNextZipEntry()) != null) {
                if (!entry.isDirectory() && isImage(entry.getName())) {
                    File tempFile = File.createTempFile("temp", null);
                    try (OutputStream os = FileUtils.openOutputStream(tempFile)) {
                        IOUtils.copy(zis, os);
                    }
                    List<Float> vector;
                    try {
                        vector = featureExtractor.getVectorFeatures(tempFile.getAbsolutePath());//提取图片一维向量
                    }catch (Exception e){
                        log.error(entry.getName()+" extract vector error",e);
                        continue;
                    }
                    String base64Image = encodeFileToBase64Binary(tempFile.getAbsolutePath());
                    images.add(new Image(entry.getName(), base64Image,LocalDateTime.now(), vector));
                    tempFile.delete(); // 删除临时文件
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 批量保存Image实体到数据库或向量数据库
        saveImages(images);
        images.clear(); // 清空列表
        System.gc(); // 提示 JVM 尽快 GC（不是强制）
        memoryCache.invalidateAll();
        return "压缩包上传成功!";
    }

    private boolean isImage(String fileName) {
        return fileName.contains("jpg") || fileName.contains("jpeg") || fileName.contains("png") || fileName.contains("gif");
    }

    private String encodeFileToBase64Binary(String fileName) throws IOException {
        File file = new File(fileName);
        FileInputStream fileInputStreamReader = new FileInputStream(file);
        byte[] bytes = new byte[(int) file.length()];
        fileInputStreamReader.read(bytes);
        return Base64.getEncoder().encodeToString(bytes);
    }
    private void saveImages(List<Image> images) {
        imageMapper.insert(images);
    }
    private boolean del(String name) {
        imageMapper.removeById(name);
        return true;
    }

    public PageResult<Image> page(ImageReq req) {
        Integer pageIndex = req.getPageIndex();
        Integer pageSize = req.getPageSize();
        String name = req.getName();

        // 🔹 缓存 Key（如果 name 为 null，就查全部）
        String cacheKey = "image:page:all-data";

        // 🔹 从缓存加载所有数据
        List<Image> allImages = memoryCache.get(cacheKey, key -> {
            System.out.println("🟠 缓存未命中，从数据库查询：" + key);

            // 这里不要传 name 条件，让缓存保留“全量数据”
            LambdaQueryWrapper<Image> queryWrapper = imageMapper.queryWrapper();

            List<VectoRexResult<Image>> query = queryWrapper.query();
            List<Image> result = new ArrayList<>();

            if (query != null && !query.isEmpty()) {
                for (VectoRexResult<Image> imageVectoRexResult : query) {
                    result.add(imageVectoRexResult.getEntity());
                }

                // ✅ 按上传时间倒序排列
                result.sort(
                        Comparator.comparing(Image::getUploadDate, Comparator.nullsFirst(Comparator.naturalOrder()))
                                .reversed()
                );
            }

            return result;
        });

        System.out.println("✅ 从缓存读取：" + cacheKey + " 共 " + allImages.size() + " 条");

        // 🔹 在内存中做模糊过滤
        List<Image> filtered = allImages;
        if (name != null && !name.trim().isEmpty()) {
            String keyword = name.toLowerCase();
            filtered = allImages.stream()
                    .filter(img -> img.getName() != null && img.getName().toLowerCase().contains(keyword))
                    .collect(Collectors.toList());
        }

        // 🔹 返回分页结果
        return PaginationUtil.paginate(filtered, pageIndex, pageSize);
    }



    public List<VectoRexResult<Image>> search(MultipartFile file, Integer topK) {
        if (!isImage(file.getContentType())) {
            throw new IllegalArgumentException("Only image files are allowed!");
        }
        try {
            // 创建临时文件
            File tempFile = File.createTempFile("temp", null);
            file.transferTo(tempFile);
            // 提取特征向量
            List<Float> vector = featureExtractor.getVectorFeatures(tempFile.getAbsolutePath());
            List<VectoRexResult<Image>> query = imageMapper.queryWrapper().vector(Image::getVector, vector).topK(topK).query();
            // 删除临时文件
            tempFile.delete();
            return query;

        } catch (IOException e) {
            throw new RuntimeException("Error processing the image file: " + e.getMessage());
        }
    }


    public String uploadFolderImage(List<MultipartFile> files) {
        final int batchSize = 10;  // 每批处理 10 张
        long totalParseMillis = 0;
        long totalSaveMillis = 0;

        for (int start = 0; start < files.size(); start += batchSize) {
            int end = Math.min(start + batchSize, files.size());
            List<MultipartFile> batch = files.subList(start, end);

            List<Image> imageBatch = new ArrayList<>();

            long batchParseStart = System.currentTimeMillis();

            for (MultipartFile file : batch) {
                if (!isImage(file.getContentType())) {
                    continue;
                }
                try {
                    File tempFile = File.createTempFile("temp", null);
                    file.transferTo(tempFile);

                    // 提取特征向量
                    List<Float> vector;
                    try {
                        vector = featureExtractor.getVectorFeatures(tempFile.getAbsolutePath());
                    } catch (Exception e) {
                        log.error(file.getOriginalFilename() + " extract vector error", e);
                        throw new RuntimeException("Error extracting vector from file: " + file.getOriginalFilename(), e);
                    }

                    String base64Image = encodeFileToBase64Binary(tempFile.getAbsolutePath());

                    String originalName = Paths.get(Objects.requireNonNull(file.getOriginalFilename())).getFileName().toString();

                    Image image = new Image(originalName, base64Image, LocalDateTime.now(), vector);
                    imageBatch.add(image);

                    tempFile.delete();

                } catch (IOException e) {
                    log.error("Error processing file: " + file.getOriginalFilename(), e);
                    throw new RuntimeException("Error processing file: " + file.getOriginalFilename(), e);
                }
            }

            long batchParseEnd = System.currentTimeMillis();
            long batchParseDuration = batchParseEnd - batchParseStart;
            totalParseMillis += batchParseDuration;
            System.out.printf("第 %d 批解析用时: %.3f 秒, 图片数量: %d%n", start / batchSize + 1, batchParseDuration / 1000.0, batch.size());
            long batchSaveStart = System.currentTimeMillis();
            saveImages(imageBatch);
            long batchSaveEnd = System.currentTimeMillis();
            long batchSaveDuration = batchSaveEnd - batchSaveStart;
            totalSaveMillis += batchSaveDuration;
            System.out.printf("第 %d 批上传用时: %.3f 秒%n", start / batchSize + 1, batchSaveDuration / 1000.0);
            imageBatch.clear();
            System.gc();
        }

        System.out.printf("总解析时间: %.3f 秒, 总上传时间: %.3f 秒%n", totalParseMillis / 1000.0, totalSaveMillis / 1000.0);
        memoryCache.invalidateAll();
        return "图片上传成功!";
    }


}
